<template>
  <div class="ttt-image" v-bind="$attrs" ref="imageDom" :style="wrapperStyle">
    <img
      v-show="!loaded"
      src="./loading.png"
      alt="ttt-images">
    <img
      v-show="loaded"
      alt="ttt-images"
      :src="currentSrc"
      :style="imageStyle"
      @load="loaded=true"
      @click="handleClick">
  </div>
  <template v-if="src instanceof Array || isVisible">
    <teleport to="body">
      <div v-if="visible" class="ttt-image-modal-bg" :style="{ zIndex }"></div>
    </teleport>
    <teleport to="body">
      <div v-if="visible" class="ttt-image-modal" :style="{ zIndex }">
        <div class="index">
          {{ currentIndex + 1 }} / {{ srcList.length }}
        </div>
        <t-tabs class="h100p" v-model="currentIndex">
          <t-tabs-item v-for="(item,index) in srcList" :key="`${item}-${index}`">
            <img :src="item" alt="ttt-images" @click="visible=false">
          </t-tabs-item>
        </t-tabs>
      </div>
    </teleport>
  </template>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { getZIndex } from '../utils/utils'
import type { PropType, CSSProperties } from 'vue'

const props = defineProps({
  // 链接地址
  src: {
    type: [String, Array] as PropType<string | string[]>,
    required: true,
    default: ''
  },
  // 大小
  size: {
    type: Array as PropType<number[]>,
    default: () => []
  },
  // 显示方式
  objectFit: {
    type: String as PropType<CSSProperties['objectFit']>,
    default: 'contain'
  },
  // 圆角
  radius: {
    type: [Boolean, String, Number] as PropType<boolean | string | number>,
    default: '8'
  },
  // 是否可以预览
  isVisible: {
    type: Boolean as PropType<boolean>,
    default: false
  },
  // 懒加载
  lazy: {
    type: Boolean as PropType<boolean>,
    default: false
  }
})

// 元素DOM
const imageDom = ref<HTMLElement>()
// 加载中
const loaded = ref<boolean>(false)
// 当前预览索引
const currentIndex = ref<number>(0)
// 当前图片地址
const currentSrc = ref<string>('')
// 预览图片地址列表
const srcList = ref<string[]>(props.src instanceof Array ? props.src : [props.src])
// 预览弹窗
const visible = ref<boolean>(false)
// 层级
const zIndex = ref<number>(getZIndex())
// style
const wrapperStyle = computed<CSSProperties>((): CSSProperties => {
  let radius
  const size = !props.size.length ? [200, 200] : props.size.length === 1 ? [props.size[0], props.size[0]] : props.size
  if (typeof props.radius === 'boolean') {
    radius = props.radius ? `9999999999999rem` : '0'
  } else {
    radius = `${props.radius}rem`
  }
  return {
    width: `${size[0]}rem`,
    height: `${size[1]}rem`,
    borderRadius: radius
  }
})
const imageStyle = computed<CSSProperties>((): CSSProperties => {
  return {
    objectFit: props.objectFit
  }
})

// 点击预览图片
const handleClick = () => {
  if (props.src instanceof Array || props.isVisible) {
    visible.value = true
  }
}

// 初始化懒加载
const initLazy = () => {
  if (!imageDom.value || !props.lazy) return
  const observer = new IntersectionObserver((entries) => {
    const src = props.src instanceof Array ? props.src[currentIndex.value] : props.src
    if (entries[0].isIntersecting && currentSrc.value !== src) {
      currentSrc.value = src
      imageDom.value && observer.unobserve(imageDom.value)
    }
  })
  observer.observe(imageDom.value)
}

// 初始化默认加载图片地址
const initImageSrc = () => {
  if (props.lazy) {
    currentSrc.value = new URL('./loading.png', import.meta.url).href
  } else {
    currentSrc.value = props.src instanceof Array ? props.src[currentIndex.value] : props.src
  }
}

onMounted(() => {
  initLazy()
  initImageSrc()
})
</script>

<style scoped lang="scss">
.ttt-image-modal-bg {
  position: fixed;
  inset: 0;
  background-color: var(--theme-modal);
}

.ttt-image-modal {
  position: fixed;
  inset: 0;
  background-color: var(--theme-modal);

  .index {
    position: absolute;
    top: 50rem;
    left: 50%;
    color: #fff;
    transform: translateX(-50%);
  }

  img {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
}

.ttt-image {
  display: inline-flex;
  background-color: var(--input-bg);
  overflow: hidden;

  img {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
}
</style>
